/*******************************************************************************
 * Copyright (c) 2000, 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package com.architexa.org.eclipse.gef.internal.ui.palette.editparts;

import com.architexa.org.eclipse.draw2d.IFigure;
import com.architexa.org.eclipse.draw2d.geometry.Dimension;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;


class EditPartTipHelper 
	extends com.architexa.org.eclipse.draw2d.PopUpHelper
{

private static EditPartTipHelper currentHelper;
private ShellListener shellListener;

private static void setHelper(EditPartTipHelper helper) {
	if (currentHelper != null && currentHelper != helper && currentHelper.isShowing())
		currentHelper.hide();
	currentHelper = helper;
}

public EditPartTipHelper(Control c) {
	super(c, SWT.ON_TOP | SWT.TOOL | SWT.NO_TRIM);
}

/**
 * Sets the LightWeightSystem object's contents  
 * to the passed tooltip, and displays the tip at 
 * the coordianates specified by tipPosX and tipPosY.  The given coordinates will be
 * adjusted if the tip cannot be completely visible on the screen.
 *
 * @param tip  The tool tip to be displayed.
 * @param tipPosX X coordiante of tooltip to be displayed
 * @param tipPosY Y coordinate of tooltip to be displayed
 */
public void displayToolTipAt(IFigure tip, int tipPosX, int tipPosY) {
	if (tip != null) {
		// Adjust the position if the tip will not be completely visible on the screen
		int shiftX = 0;
		int shiftY = 0;
		Dimension tipSize = tip.getPreferredSize();
		getShell();
		tipSize = tipSize.getExpanded(getShellTrimSize());
		org.eclipse.swt.graphics.Rectangle area = control.getDisplay().getClientArea();
		org.eclipse.swt.graphics.Point end = new org.eclipse.swt.graphics.Point(
					tipPosX + tipSize.width, tipPosY + tipSize.height);
		if (!area.contains(end)) {
			shiftX = end.x - (area.x + area.width);
			shiftY = end.y - (area.y + area.height);
			shiftX = shiftX < 0 ? 0 : shiftX;
			shiftY = shiftY < 0 ? 0 : shiftY;
		}
		tipPosX -= shiftX;
		tipPosY -= shiftY;
		
		// Display the tip
		EditPartTipHelper.setHelper(this);
		getLightweightSystem().setContents(tip);
		setShellBounds(tipPosX, tipPosY, tipSize.width, tipSize.height);
		show();
		getShell().setCapture(true);
	}
}

public void dispose() {
	if (shellListener != null) {
		control.getShell().removeShellListener(shellListener);
		shellListener = null;
	}
	super.dispose();
}

/**
 * @see com.architexa.org.eclipse.draw2d.PopUpHelper#hide()
 */
protected void hide() {
	super.hide();
	currentHelper = null;
}

protected void hookShellListeners() {

	/* If the cursor leaves the tip window, hide the tooltip and
	   dispose of its shell */
	getShell().addMouseTrackListener(new MouseTrackAdapter() {
		public void mouseExit(MouseEvent e) {
			getShell().setCapture(false);	
			dispose();
		}
	});
	/* If the mouseExit listener does not get called,
	   dispose of the shell if the cursor is no longer in the 
	   tooltip. This occurs in the rare case that a mouseEnter 
	   is not received on the tooltip when it appears.*/
	getShell().addMouseMoveListener(new MouseMoveListener() {
		public void mouseMove(MouseEvent e) {
			Point eventPoint = getShell().toDisplay(new Point(e.x, e.y));
			if (!getShell().getBounds().contains(eventPoint)) {
				if (isShowing())
					getShell().setCapture(false);
				dispose();
			}
		}
	});
	
	//This is to dispose of the tooltip when the user ALT-TABs to another window.
	if (shellListener == null) {
		shellListener = new ShellAdapter() {
			public void shellDeactivated(ShellEvent event) {
				Display.getCurrent().asyncExec(new Runnable() {
					public void run() {
						Shell active = Display.getCurrent().getActiveShell();
						if (getShell() == active || control.getShell() == active || getShell().isDisposed())
							return;
						if (isShowing())
							getShell().setCapture(false);
						dispose();
					}
				});
			}
		};
		control.getShell().addShellListener(shellListener);
		getShell().addShellListener(shellListener);
	}
	
	/* Workaround for GTK Bug - Control.setCapture(boolean) not implemented: 
	   If the cursor is not over the shell when it is first painted, 
	   hide the tooltip and dispose of the shell. */
	if (SWT.getPlatform().equals("gtk")) {  //$NON-NLS-1$
		getShell().addPaintListener(new PaintListener() {
			public void paintControl(PaintEvent event) {
				Point cursorLoc = Display.getCurrent().getCursorLocation();
				if (!getShell().getBounds().contains(cursorLoc)) {
					// This must be run asynchronously.  If not, other paint 
					// listeners may attempt to paint on a disposed control.
					Display.getCurrent().asyncExec(new Runnable() {
						public void run() {
							if (isShowing())
								getShell().setCapture(false);
							dispose();
						}
					});
				}
			}
		});
	}
}

public static boolean isCurrent(EditPartTipHelper helper) {
	return currentHelper != null && helper == currentHelper;
}

}
